package com.corpgovernment.organization.service.impl;

import com.corpgovernment.api.basic.dto.OrgDTO;
import com.corpgovernment.api.basic.enums.SourceEnum;
import com.corpgovernment.api.basic.vo.MbUserLoginRecordVo;
import com.corpgovernment.api.basic.vo.MbUserRegisterIdentityVO;
import com.corpgovernment.api.basic.vo.MbUserRegisterRequestVO;
import com.corpgovernment.api.basic.vo.UserLoginResponseVo;
import com.corpgovernment.api.organization.bo.GetUserInfoRequestBO;
import com.corpgovernment.api.organization.enums.LoginTypeEnum;
import com.corpgovernment.common.apollo.OrganizationApollo;
import com.corpgovernment.common.base.BaseUserInfo;
import com.corpgovernment.common.base.CommonException;
import com.corpgovernment.common.holder.TenantContextHolder;
import com.corpgovernment.common.utils.Md5Util;
import com.corpgovernment.organization.convert.LoginConvert;
import com.corpgovernment.organization.dataloader.db.MbOrgEmployeeLoader;
import com.corpgovernment.organization.dataloader.db.MbUserLoginLoader;
import com.corpgovernment.organization.entity.db.MbOrgEmployeeInfo;
import com.corpgovernment.organization.entity.db.MbUserLogin;
import com.corpgovernment.organization.enumm.ERedisKeyType;
import com.corpgovernment.organization.enumm.ValidEnum;
import com.corpgovernment.organization.service.IUserLoginRecordService;
import com.corpgovernment.organization.util.OrganizationUtils;
import com.corpgovernment.organization.util.TokenValidUtil;
import com.corpgovernment.permission.service.UserService;
import com.corpgovernment.redis.cache.RedisUtils;
import com.ctrip.corp.obt.async.redis.RedisClientDelegate;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

import static com.corpgovernment.api.basic.metadata.ELoginStatus.USERNAME_INCORRECT;
import static com.corpgovernment.organization.controller.OrganizationController.ORG_DISABLE;
import static com.corpgovernment.organization.enumm.ERedisKeyType.USER_REGISTER_VALID_TOKEN;
import static com.corpgovernment.organization.util.TokenValidUtil.USER_ORG_DISABLE;

/**
 * @author jhxue
 * @create 2022-02-18-14:19
 */
@Slf4j
public abstract class AbstractLoginSourceService {

	@Autowired
	private MbUserLoginLoader mbUserLoginLoader;
	@Autowired
	private MbOrgEmployeeLoader mbOrgEmployeeLoader;
	@Autowired
	private RedisUtils redisUtils;
	@Autowired
	private OrganizationApollo organizationApollo;
	@Autowired
	private IUserLoginRecordService userLoginRecordService;
	@Autowired
	private LoginConvert loginConvert;
	@Autowired
	private UserService userService;
	@Autowired
	private RedisClientDelegate redisClientDelegate;

	/**
	 * 登录
	 *
	 * @param userInfo
	 * @param response
	 * @param loginType
	 * @return
	 */
	public abstract UserLoginResponseVo process(BaseUserInfo userInfo, UserLoginResponseVo response, LoginTypeEnum loginType);


	/**
	 * 登录方式
	 *
	 * @return
	 */
	public abstract SourceEnum[] getLoginSource();


//	/**
//	 * 确认身份登录(前台)
//	 *
//	 * @param request 确认身份登录请求
//	 * @return 确认身份结果
//	 */
//	public UserLoginResponseVo confirmLogin(UserLoginRequest request){
//		String source = request.getSource();
//		String token = request.getToken();
//		BaseUserInfo userInfo = redisUtils.getCache(source + ":" + token, BaseUserInfo.class);
//		redisUtils.delete(source + ":" + token);
//		if (Objects.isNull(userInfo)) {
//			throw new CommonException(ELoginStatus.TOKEN_INVALID.getValue(), ELoginStatus.TOKEN_INVALID.getDesc());
//		}
//		String uid = userInfo.getUid();
//		String deptId = request.getDeptId();
//		String corpId = request.getCorpId();
//		String deptName = request.getDeptName();
//		String corpName = request.getCorpName();
//		String orgId = StringUtils.isBlank(deptId) ? corpId : deptId;
//		// 查询用户组织信息,并判断当前组织公司是否可用,不可用不能登录,判断用户身份是否可用
//		// 身份状态1正常，0待审核 只有正常状态可以登录
//		UserLoginResponseVo response = new UserLoginResponseVo();
//		if (!OrganizationUtils.checkIdentity(uid, orgId)) {
//			throw new CommonException(100003, "用户身份认证失败");
//		}
//		userInfo.setOrgId(deptId).setOrgName(deptName).setCorpId(corpId).setCorpName(corpName);
//		token = genLoginToken(userInfo.getAccountName(), userInfo.getUid());
//		userInfo.setToken(token);
//		redisUtils.setCache(source + ":" + token, userInfo, organizationApollo.getLoginTimeOut());
//		log.info("登录时长：{}", organizationApollo.getLoginTimeOut());
//		response.setToken(token).setUid(userInfo.getUid()).setAccountName(userInfo.getAccountName())
//				.setUserName(userInfo.getUserName()).setBgUser(userInfo.getBgUser())
//				.setIdentityShowStr(StringUtils.equals(corpId, deptId) ? corpName : corpName + ">" + deptName);
//		if (userInfo.getBgUser()) {
//			// 后台登录获取菜单
//			List<String> menuList = userService.getUserPermissionList(GetUserPermissionListRequest.create(uid, corpId));
//			response.setMenuList(menuList);
//			return response;
//		}
//		response.setShowManage(CollectionUtils.isNotEmpty(OrganizationUtils.getIdentityList(uid, deptId)));
//		MbUserLoginRecordVo mbUserLoginRecordVo = new MbUserLoginRecordVo();
//		mbUserLoginRecordVo.setUid(uid);
//		mbUserLoginRecordVo.setCorpid(corpId);
//		mbUserLoginRecordVo.setCorpName(corpName);
//		mbUserLoginRecordVo.setOrgid(orgId);
//		mbUserLoginRecordVo.setOrgName(deptName);
//		mbUserLoginRecordVo.setSource(source);
//		mbUserLoginRecordVo.setToken(token);
//		mbUserLoginRecordVo.setUserName(userInfo.getUserName());
//		log.info("用户确认身份登录(APP/PCBOOK)-------------,{}", JsonUtils.toJsonString(mbUserLoginRecordVo));
//		userLoginRecordService.insert(mbUserLoginRecordVo);
//		return response;
//
//	}

	/**
	 * 注册身份
	 *
	 * @param userOrgMap
	 * @param baseUserInfo
	 * @param response
	 */
	protected void registerIdentity(Map<Integer, List<OrgDTO>> userOrgMap, BaseUserInfo baseUserInfo, UserLoginResponseVo response) {
		// 没有审核通过身份需要跳转到注册页面标识
		response.setNoOrgFlag(true);
		checkApprovalStatus(userOrgMap.get(0));
		List<OrgDTO> orgVoS = userOrgMap.get(0);
		MbUserRegisterRequestVO mbUserRegisterRequestVO = new MbUserRegisterRequestVO()
				.setUid(baseUserInfo.getUid()).setAccountName(baseUserInfo.getAccountName()).setSource(baseUserInfo.getSource())
				.setRoleList(new HashSet<>(loginConvert.convert(orgVoS, "待审核")));
		// 用户信息保存到缓存
		redisUtils.setCache(ERedisKeyType.USER_ORG_REGISTER_TOKEN.getKey(baseUserInfo.getAccountName()), mbUserRegisterRequestVO, organizationApollo.getUserRegisterValidTokenTimeOut() * 60L);
		String validToken = UUID.randomUUID().toString();
		redisUtils.setCache(USER_REGISTER_VALID_TOKEN.getKey(validToken), validToken, organizationApollo.getUserRegisterValidTokenTimeOut() * 60L);
		response.setValidToken(validToken);
	}

	/**
	 * 设置身份
	 *
	 * @param userOrgMap
	 * @param baseUserInfo
	 * @param response
	 */
	protected void setIdentity(Map<Integer, List<OrgDTO>> userOrgMap, BaseUserInfo baseUserInfo, UserLoginResponseVo response) {
		checkApprovalStatus(userOrgMap.get(2));
		response.setIdentityList(loginConvert.convert(userOrgMap.get(2), "待审核"));
//		String key = baseUserInfo.getSource() + ":" + baseUserInfo.getToken();
//		redisUtils.setCache(key, baseUserInfo, 60L);
//		log.info("校验验证码塞入缓存的key：" + key);
	}

	/**
	 * 登陆成功
	 *
	 * @param userOrgMap
	 * @param userInfo
	 * @param response
	 */
	protected void loginSuccess(Map<Integer, List<OrgDTO>> userOrgMap, BaseUserInfo userInfo, UserLoginResponseVo response) {
		// 有且仅有一个审核通过的身份直接登录成功标志
		OrgDTO orgDTO = userOrgMap.get(1).get(0);
		String corpId = orgDTO.getCorpId();
		String deptId = orgDTO.getDeptId();
		String corpName = orgDTO.getCorpName();
		String deptName = orgDTO.getDeptName();
		userInfo.setCorpId(corpId).setOrgId(deptId).setCorpName(corpName).setOrgName(deptName);
		response.setIdentityList(null).setCorpId(corpId).setOrgId(deptId).setCorpName(corpName).setOrgName(deptName);
		response.setIdentityShowStr(StringUtils.equals(corpId, deptId, false) ? corpName : corpName + ">" + deptName);
//		redisUtils.setCache(userInfo.getSource() + ":" + userInfo.getToken(), userInfo, organizationApollo.getLoginTimeOut());
		log.info("登录时长：{}", organizationApollo.getLoginTimeOut());
		if (CollectionUtils.isNotEmpty(OrganizationUtils.getIdentityList(userInfo.getUid(), deptId))) {
			response.setShowManage(true);
		}
		MbUserLoginRecordVo mbUserLoginRecordVo = new MbUserLoginRecordVo();
		mbUserLoginRecordVo.setUid(userInfo.getUid());
		mbUserLoginRecordVo.setCorpid(corpId);
		mbUserLoginRecordVo.setCorpName(corpName);
		mbUserLoginRecordVo.setOrgid(deptId);
		mbUserLoginRecordVo.setOrgName(deptName);
		mbUserLoginRecordVo.setSource(userInfo.getSource());
		mbUserLoginRecordVo.setToken(userInfo.getToken());
		mbUserLoginRecordVo.setUserName(userInfo.getUserName());
		log.info("验证用户-------------,{}", JsonUtils.toJsonString(mbUserLoginRecordVo));
		userLoginRecordService.insert(mbUserLoginRecordVo);
	}

	/**
	 * 是否无可用身份
	 *
	 * @param userOrgMap
	 * @return
	 */
	protected boolean noIdentity(Map<Integer, List<OrgDTO>> userOrgMap) {
		return OrganizationUtils.checkIdentity(-1, userOrgMap) ||
				OrganizationUtils.checkIdentity(0, userOrgMap);
	}

	/**
	 * 是否拥有多个有效身份
	 *
	 * @param userOrgMap
	 * @return
	 */
	protected boolean selectIdentity(Map<Integer, List<OrgDTO>> userOrgMap) {
		return OrganizationUtils.checkIdentity(2, userOrgMap);
	}

	/**
	 * 是否只有一个有效身份
	 *
	 * @param userOrgMap
	 * @return
	 */
	protected boolean oneIdentity(Map<Integer, List<OrgDTO>> userOrgMap) {
		return OrganizationUtils.checkIdentity(1, userOrgMap);
	}

	/**
	 * 校验用户身份审核审核状态
	 *
	 * @param orgList
	 */
	protected void checkApprovalStatus(List<OrgDTO> orgList) {
		if (CollectionUtils.isEmpty(orgList)) {
			return;
		}
		for (OrgDTO org : orgList) {
			Optional.ofNullable(org).map(OrgDTO::getApprovalStatus).orElseThrow(() -> new CommonException(1100010, "用户身份审核状态为空"));
		}
	}


	/**
	 * 数据转换
	 *
	 * @param orgList
	 * @param state
	 * @return
	 */
	protected List<MbUserRegisterIdentityVO> convert(List<OrgDTO> orgList, String state) {
		if (CollectionUtils.isEmpty(orgList)) {
			return new ArrayList<>();
		}
		return orgList.stream().filter(Objects::nonNull).map(e -> {
			MbUserRegisterIdentityVO target = new MbUserRegisterIdentityVO();
			target.setDeptId(e.getDeptId());
			target.setDeptName(e.getDeptName());
			target.setCorpId(e.getCorpId());
			target.setCorpName(e.getCorpName());
			target.setState(e.getApprovalStatus() == 1 ? "审核通过" : state);
			target.setStatus(e.getApprovalStatus());
			return target;
		}).collect(Collectors.toList());
	}


	/**
	 * 获取用户信息
	 *
	 * @param request
	 * @return
	 */
	protected BaseUserInfo getUserInfo(GetUserInfoRequestBO request) {
		String uid = request.getUid();
		MbOrgEmployeeInfo employeeInfo = this.findEmployeeInfoByUid(uid);
		if (employeeInfo == null) {
			throw new CommonException(USERNAME_INCORRECT.getValue(), USERNAME_INCORRECT.getDesc());
		}
		MbUserLogin mbUserLogin = this.findUserLoginByUid(uid);
		if (mbUserLogin == null) {
			throw new CommonException(USERNAME_INCORRECT.getValue(), USERNAME_INCORRECT.getDesc());
		}
		String accountName = mbUserLogin.getAccountName();
		String token = request.getToken();
		String userName = mbUserLogin.getUserName();
		Boolean isBgUser = mbUserLogin.getBgUser() == 1;
		String source = request.getSource();
		BaseUserInfo userInfo = new BaseUserInfo()
				.setUid(uid).setUserName(userName).setToken(token)
				.setBgUser(isBgUser).setAccountName(accountName).setSource(source);
//		String identityId = source + ":" + token;

		List<OrgDTO> orgInfoByUid = OrganizationUtils.getOrgInfoByUid(uid);
		Optional<OrgDTO> first = orgInfoByUid.stream().filter(item -> item.getDeptId().equals(request.getOrgId())).findFirst();
		if (first.isPresent()){
			OrgDTO orgDTO = first.get();
			userInfo.setCorpId(orgDTO.getCorpId()).setOrgId(orgDTO.getDeptId()).setCorpName(orgDTO.getCorpName()).setOrgName(orgDTO.getDeptName());
		}
//		redisUtils.setCache(identityId, userInfo, organizationApollo.getLoginTimeOut());
		return userInfo;
	}

	/**
	 * 获取用户信息
	 *
	 * @param request
	 * @return
	 */
	protected BaseUserInfo getUserInfoV2(GetUserInfoRequestBO request) {
		log.info("userInfoV2 ==> request:{}", JsonUtils.toJsonString(request));
		String uid = request.getUid();
		MbOrgEmployeeInfo employeeInfo = this.findEmployeeInfoByUid(uid);
		log.info("userInfoV2 ==> employeeInfo:{}", JsonUtils.toJsonString(employeeInfo));
		if (employeeInfo == null) {
			return null;
		}
		MbUserLogin mbUserLogin = this.findUserLoginByUid(uid);
		log.info("userInfoV2 ==> mbUserLogin:{}", JsonUtils.toJsonString(mbUserLogin));
		if (mbUserLogin == null) {
			return null;
		}

		String accountName = mbUserLogin.getAccountName();
		String userName = mbUserLogin.getUserName();
		Boolean isBgUser = mbUserLogin.getBgUser() == 1;
		BaseUserInfo userInfo = new BaseUserInfo()
				.setUid(uid).setUserName(userName)
				.setBgUser(isBgUser).setAccountName(accountName);
//		String identityId = TenantContext.getTenantId() + ":" + uid;
		log.info("userInfoV2 ==> mbUserLogin:{}", JsonUtils.toJsonString(mbUserLogin));

		List<OrgDTO> orgInfoByUid = OrganizationUtils.getOrgInfoByUid(uid);

		if (CollectionUtils.isNotEmpty(orgInfoByUid)) {
			Map<String, BaseUserInfo.Org> orgGroup = new HashMap<>(orgInfoByUid.size());
			for (OrgDTO orgDTO : orgInfoByUid) {
				BaseUserInfo.Org org = new BaseUserInfo.Org();
				org.setCorpId(orgDTO.getCorpId());
				org.setCorpName(orgDTO.getCorpName());
				org.setOrgId(orgDTO.getDeptId());
				org.setOrgName(orgDTO.getDeptName());
				orgGroup.put(orgDTO.getDeptId(), org);
			}
			userInfo.setOrgGroup(orgGroup);
		}

        log.info("Get user info: {}", JsonUtils.toJsonString(userInfo));
		log.info("Get user org info: {}", JsonUtils.toJsonString(orgInfoByUid));
		Optional<OrgDTO> first = orgInfoByUid.stream().filter(item -> item.getDeptId().equals(request.getOrgId())).findFirst();
		if (first.isPresent()){
			OrgDTO orgDTO = first.get();
			userInfo.setCorpId(orgDTO.getCorpId()).setOrgId(orgDTO.getDeptId()).setCorpName(orgDTO.getCorpName()).setOrgName(orgDTO.getDeptName());
		}
		List<String> keys = Lists.newArrayList();
		keys.add(TokenValidUtil.USER_DISABLE + ":" + (StringUtils.isEmpty(userInfo.getSupplierCode()) ? userInfo.getUid() : String.join(",", userInfo.getUid(), userInfo.getSupplierCode())));
		keys.add(ORG_DISABLE + ":" + userInfo.getOrgId());
		keys.add(USER_ORG_DISABLE + ":" + userInfo.getUid() + "-" + userInfo.getOrgId());
		List<Object> values = redisClientDelegate.withCommandsClient(c -> {
			return c.multiGet(keys);
		});
		log.info("Disabled flag: {}, valid flag: {}", JsonUtils.toJsonString(values), employeeInfo.getValid());
		boolean disabled = values.stream().anyMatch(Objects::nonNull);
		userInfo.setValid(ValidEnum.T.equals(ValidEnum.getByCode(employeeInfo.getValid())) && !disabled);
		userInfo.setStatus(mbUserLogin.getStatus());
//		redisUtils.setCache(identityId, userInfo, organizationApollo.getLoginTimeOut());
		return userInfo;
	}

//	protected MbOrgEmployeeInfo findByUid(String uid) {
//		MbOrgEmployeeInfo record = new MbOrgEmployeeInfo();
//		record.setUid(uid);
//		record.setDeleteTime(new Date(0));
//		return mbOrgEmployeeLoader.selectOneByRecord(record);
//	}

	protected MbOrgEmployeeInfo findEmployeeInfoByUid(String uid) {
		MbOrgEmployeeInfo record = new MbOrgEmployeeInfo();
		record.setUid(uid);
		record.setDeleteTime(new Date(0));
		return mbOrgEmployeeLoader.selectOneByRecord(record);
	}

	/**
	 * 生成登录token
	 *
	 * @param pwd 密码/验证码
	 * @param uid 用户账号/手机号
	 * @return token
	 */
	protected String genLoginToken(String pwd, String uid) {
		String tenantId = TenantContextHolder.getTenantId();
		return Md5Util.encodeMd5WithRandomSalt(tenantId + uid + pwd);
	}

	/**
	 * 根据账号和是否后台用户查询
	 *
	 * @param accountName
	 * @return
	 */
	protected MbUserLogin getByAccountName(String accountName) {
		MbUserLogin record = new MbUserLogin();
		record.setAccountName(accountName);
		record.setDeleteTime(new Date(0));
		MbUserLogin mbUserLogin = mbUserLoginLoader.selectOneByRecord(record);
		if (mbUserLogin == null) {
			record.setAccountName("+86" + accountName);
			record.setDeleteTime(new Date(0));
			mbUserLogin = mbUserLoginLoader.selectOneByRecord(record);
		}
		return mbUserLogin;
	}

	/**
	 * 根据账号和是否后台用户查询
	 *
	 * @param uid
	 * @return
	 */
	protected MbUserLogin findUserLoginByUid(String uid) {
		MbUserLogin record = new MbUserLogin();
		record.setUid(uid);
		record.setDeleteTime(new Date(0));
		return mbUserLoginLoader.selectOneByRecord(record);
	}


}
